package com.example.demo.service;

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.timelimiter.annotation.TimeLimiter;
import io.minio.GetObjectArgs;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.http.Method;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Service
public class FileService {

    private final MinioClient minioClient;
    private final String bucketName;

    public FileService(MinioClient minioClient, @Value("${minio.bucket}") String bucketName) {
        this.minioClient = minioClient;
        this.bucketName = bucketName;
    }

    // 上传文件，避免临时文件存储
    public String uploadFile(MultipartFile file) throws Exception {
        String fileName = file.getOriginalFilename();

        // 使用 InputStream 上传文件
        try (InputStream inputStream = file.getInputStream()) {
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName)
                            .stream(inputStream, file.getSize(), -1)
                            .build());
        }
        return fileName; // 返回上传文件的文件名
    }

    // 下载文件，避免临时文件存储
    public void downloadFile(String fileName, OutputStream outputStream) throws Exception {
        try (InputStream inputStream = minioClient.getObject(
                GetObjectArgs.builder().bucket(bucketName).object(fileName).build())) {

            byte[] buffer = new byte[8192]; // 8 KB buffer
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
    }

    // 获取预签名下载 URL
    public String getPresignedDownloadUrl(String fileName, int expiry) throws Exception {
        // 使用 GetPresignedObjectUrlArgs 构建获取预签名 URL 的参数
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .method(Method.GET)
                .object(fileName)
                .expiry(expiry, TimeUnit.DAYS)
                .build();

        // 获取预签名的 URL
        String presignedObjectUrl = minioClient.getPresignedObjectUrl(args);

        return presignedObjectUrl; // 返回预签名 URL
    }

    // 文件流下载
    public void downloadStream(String filename, boolean isPreview, HttpServletResponse response) throws Exception {
        try (InputStream inputStream = minioClient.getObject(
                GetObjectArgs.builder().bucket(bucketName).object(filename).build())) {

            // URL encode the filename to ensure Unicode compatibility
            String encodedFileName = URLEncoder.encode(filename, StandardCharsets.UTF_8).replace("+", "%20");

            // Get MIME type of the file
            String mimeType = getMimeType(filename);

            // 判断是否支持预览
            if (isPreview && isPreviewAble(mimeType)) {
                // 设置为浏览器预览
                response.setContentType(mimeType);
                response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=" + encodedFileName);
            } else {
                // 设置为下载
                response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
                response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + encodedFileName);
            }

            // 将文件输出到响应
            IOUtils.copy(inputStream, response.getOutputStream());
            response.flushBuffer();
        }
    }

    /**
     * 获取文件的 MIME 类型
     */
    private String getMimeType(String filename) {
        // 使用 java.nio.file.Files.probeContentType 解析 MIME 类型
        try {
            return java.nio.file.Files.probeContentType(java.nio.file.Paths.get(filename));
        } catch (Exception e) {
            // 如果无法确定 MIME 类型，返回默认类型
            return MediaType.APPLICATION_OCTET_STREAM_VALUE;
        }
    }

    /**
     * 判断文件是否支持浏览器预览（仅限浏览器原生支持的类型）
     */
    private boolean isPreviewAble(String mimeType) {
        if (mimeType == null) {
            return false;
        }

        // 浏览器原生支持预览的 MIME 类型
        return mimeType.startsWith("image/") ||                // 图片类型，如 image/jpeg, image/png, image/gif
                mimeType.equals("application/pdf") ||           // PDF 文件
                mimeType.startsWith("text/") ||                 // 文本文件
                mimeType.startsWith("audio/") ||                // 音频文件，如 audio/mpeg, audio/wav
                mimeType.startsWith("video/");                  // 视频文件，如 video/mp4, video/webm
    }

    @CircuitBreaker(name = "backendA")
    @TimeLimiter(name = "backendA")
    public CompletableFuture<String> hello() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "Hello World";
        });
    }
}

